use structopt::StructOpt;

use crate::errors::Error;
use crate::spec;

#[derive(StructOpt, Debug)]
#[structopt(name = "rustime", about = "container runtime by rust")]
pub struct Opt {
    /// debug mode
    #[structopt(long)]
    pub debug: bool,

    /// log file
    #[structopt(long, default_value = "/dev/null")]
    pub log: String,

    /// log format
    #[structopt(long, default_value = "text")]
    pub log_format: String,

    /// log level
    #[structopt(long, default_value = "info")]
    pub log_level: String,

    /// root path
    #[structopt(long, default_value = "/run/rustime")]
    pub root: String,

    /// subcommand
    #[structopt(subcommand)]
    pub cmd: Commands,
}

impl Opt {
    pub fn new() -> Opt {
        Opt::from_args()
    }
}

#[derive(StructOpt, Debug)]
#[structopt(about = "container runtime by rust")]
pub enum Commands {
    /// create container instance
    #[structopt(name = "create")]
    Create(CreateArgs),

    /// init process
    #[structopt(name = "init")]
    Init(InitArgs),

    /// start container instance
    #[structopt(name = "start")]
    Start(StartArgs),

    /// delete container instance
    #[structopt(name = "delete")]
    Delete(DeleteArgs),

    /// state container instance
    #[structopt(name = "state")]
    State(StateArgs),
}

#[derive(StructOpt, Debug)]
pub struct CreateArgs {
    /// bundle path
    #[structopt(short, long, default_value = ".")]
    pub bundle: String,

    /// file to write pid
    #[structopt(long, default_value = "")]
    pub pid_file: String,

    /// console socket
    #[structopt(long, default_value = "")]
    pub console_socket: String,

    #[structopt()]
    pub id: String,
}

#[derive(StructOpt, Debug)]
pub struct InitArgs {
    #[structopt()]
    pub id: String,
}

#[derive(StructOpt, Debug)]
pub struct StartArgs {
    #[structopt()]
    pub id: String,
}

#[derive(StructOpt, Debug)]
pub struct DeleteArgs {
    #[structopt(short, long)]
    pub force: bool,

    #[structopt()]
    pub id: String,
}

#[derive(StructOpt, Debug)]
pub struct StateArgs {
    #[structopt()]
    pub id: String,
}

pub fn handle(opt: &Opt) -> Result<(), Error> {
    match &opt.cmd {
        Commands::Create(args) => return do_create(opt, args),
        Commands::Init(args) => return do_init(opt, args),
        Commands::Start(args) => return do_start(opt, args),
        Commands::State(args) => return do_state(opt, args),
        Commands::Delete(args) => return do_delete(opt, args),
    };
}

pub fn do_create(_opt: &Opt, args: &CreateArgs) -> Result<(), Error> {
    let fcfg = [&args.bundle, "config.json"].join("/");
    let _spec = spec::load_spec(&fcfg)?;
    Ok(())
}

pub fn do_init(_opt: &Opt, _args: &InitArgs) -> Result<(), Error> {
    Ok(())
}

pub fn do_start(_opt: &Opt, _args: &StartArgs) -> Result<(), Error> {
    Ok(())
}

fn do_state(_opt: &Opt, _args: &StateArgs) -> Result<(), Error> {
    Ok(())
}

fn do_delete(_opt: &Opt, _args: &DeleteArgs) -> Result<(), Error> {
    Ok(())
}
